package myJs.user.soft.violinPlot

import com.softwaremill.quicklens._
import myJs.Implicits._
import myJs.Utils.layer
import myJs.api.Api
import myJs.cps._
import myJs.myPkg._
import myJs.myPkg.reactHookForm._
import myJs.tool.Tool
import myJs.tool.Tool.messages
import org.scalajs.dom.{html, window}
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import shared.Pojo.MetDataKind
import shared.pojo.GroupFileData.GetGroups
import shared.pojo.Pojo
import shared.pojo.Pojo.workflowMission._
import shared.pojo.mission._
import shared.tool.DefaultPickle
import upickle.default._

import scala.collection.immutable.SeqMap
import scala.scalajs.js
import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js.JSON

import japgolly.scalajs.react.vdom.all._
import japgolly.scalajs.react._
import japgolly.scalajs.react.React.Fragment
import japgolly.scalajs.react.util.EffectCatsEffect._
import myJs.myPkg.Hooks._
import cats.effect._
import myJs.Implicits._
import myJs.Utils._
import cats.syntax.all._

/** Created by yz on 3/11/2020
  */
object Cp {

  case class Props(missionName: String){
    @inline def render: VdomElement = {
      Component(this)
    }
  }

  val Component = ScalaFnComponent[Props] { props =>
    val useForm = ReactHookForm.useForm(UseFormOptions(mode = "onChange", resolver = yupResolver(Schema.schema)))
    val (myData, setMyData) = useState(ViolinPlotSoftData(missionName = props.missionName))
    val (extraData, setExtraData) = useState(ExtraData())

    object FTool {

      def groupFileSelect = (v: String) => {
        setExtraData { x =>
          x.modify(_.fileSelectShow).setTo(false)
        } >>
        setMyData { x =>
          x.modify(_.groupFile).setTo(v)
        }
      }.unsafeRunSync()

      def groupFileSelectShow = {
        if (myData.file.isEmpty) SyncIO{
          useForm.trigger("file")
        } else {
          val newRequest = Pojo.groupFileData.GetAll.Request(fileName = myData.file)
          val newData = extraData
            .modify(_.tabs)
            .setTo(List("group", "example"))
            .modify(_.request)
            .setTo(newRequest)
            .modify(_.fileSelectShow)
            .setTo(true)
            .modify(_.exampleFileName)
            .setTo("group.txt")
            .modify(_.fileSelect)
            .setTo(FTool.groupFileSelect)
          setExtraData(newData)
        }
      }

      def strChange(f: PathLazyModify[ViolinPlotSoftData, String]) = (v: String) => {
        setMyData {
          f.setTo(v)
        }
      }

      def vChange[T](f: PathLazyModify[ViolinPlotSoftData, T]) = (v: T) => {
        setMyData {
          f.setTo(v)
        }
      }

      def extraDataVChange[T](f: PathLazyModify[ExtraData, T]) = (v: T) => {
        setExtraData {
          f.setTo(v)
        }
      }

      def fileSelect = (v: String) => {
        setExtraData { x =>
          x.modify(_.fileSelectShow).setTo(false)
        } >>
        setMyData { x =>
          x.modify(_.file)
            .setTo(v)
            .modify(_.groupFile)
            .setTo("")
        }
      }.unsafeRunSync()

      def fileSelectShow = {
        val newData = extraData
          .modify(_.tabs)
          .setTo(List(MetDataKind.name, "example"))
          .modify(_.fileSelectShow)
          .setTo(true)
          .modify(_.exampleFileName)
          .setTo("data.txt")
          .modify(_.fileSelect)
          .setTo(FTool.fileSelect)
        setExtraData(newData)
      }

      def inputSelect = (inputE: html.Input) => {
        inputE.select()
      }

      def myRun = () => {
        val layerOptions = LayerOptions.title(Tool.zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
        val index = layer.alert(Tool.myElement, layerOptions)
        val request = DefaultPickle.write(myData)
        Api.soft.analysis(request).map { response =>
          layer.close(index)
          if (response.valid) {
            window.location.href = g.jsRoutes.controllers.MissionController.missionManageBefore().url.toString
          } else {
            g.swal("Error", response.message, "error")
          }
        }
        ()
      }

      def getGroups = {
        val request =
          GetGroups.Request(file = myData.file, groupFile = myData.groupFile)
        Api.groupFileData.getGroups(request).map { response =>
          response
        }
      }

      def getCanPaired = () => {
        val request = CanPaired
          .Request(file = myData.file, groupFile = myData.groupFile)
        Api.mission.canPaired(request)
      }

      def refreshExtraData = {
        (FTool.getGroups,FTool.getCanPaired()).tupled.flatMapSync { case (groups, canPaired) =>
          setExtraData { x =>
            x.modify(_.groups)
              .setTo(groups)
              .modify(_.canPaired)
              .setTo(canPaired)
          }
        }
      }

      def formSubmit = useForm.handleSubmit((data: js.Dictionary[js.Any]) => {
        println(JSON.stringify(data))
        FTool.myRun()
      })

    }

    useEffect(
      {
        val missionId = Tool.getMissionId
        if (missionId.nonBlank) {
          Api.mission.getConfigData(missionId).flatMapSync { response =>
            val responseData = read[ViolinPlotSoftData](response)
            val curMyData = responseData.modify(_.missionName).setTo(props.missionName)
            setMyData(curMyData) >> SyncIO{
              useForm.reset(curMyData)
            }
          }
        }else IO.unit
      },
      List()
    )

    useEffect(
      {
        if (myData.file.nonBlank && myData.groupFile.nonBlank) {
          FTool.refreshExtraData
        }else IO.unit
      },
      List(myData.file, myData.groupFile)
    )

    val methodMap = SeqMap("auto" -> messages("wiseChoose")) ++ {
      if (extraData.groups.size > 2) {
        SeqMap("kw" -> messages("kruskalWallisTest"), "anova" -> messages("anovaTest"))
      } else {
        SeqMap("u" -> messages("uTest"), "t" -> messages("tTest"))
      }
    }

    FormProvider(
      trigger = useForm.trigger _,
      control = useForm.control,
      formState = useForm.formState,
      setValue = useForm.setValue _,
      watch = useForm.watch _,
      getFieldState = useForm.getFieldState _
    )(
      form(
        onSubmit := FTool.formSubmit,
        className := "form-horizontal",
        InputInlineCp.Props(
          name = "missionName",
          label = messages("taskName"),
          onChange = FTool.strChange(modifyLens[ViolinPlotSoftData](_.missionName)),
          value = myData.missionName,
          onFocus = FTool.inputSelect
        ).render,
        FileSelectInlineCp.Props(
          fileSelectShow = FTool.fileSelectShow,
          label = messages("dataMatrix"),
          name = "file",
          value = myData.file,
          onChange = FTool.strChange(modifyLens[ViolinPlotSoftData](_.file)),
          inputWidth = 4
        ).render,
        FileSelectInlineCp.Props(
          fileSelectShow = FTool.groupFileSelectShow,
          label = messages("groupFile"),
          name = "groupFile",
          value = myData.groupFile,
          onChange = FTool.strChange(modifyLens[ViolinPlotSoftData](_.groupFile)),
          inputWidth = 4
        ).render,
        ToggleInlineCp.Props(
          value = myData.isPaired,
          label = messages("paired"),
          name = s"isPaired",
          valueChange = FTool.vChange(modifyLens[ViolinPlotSoftData](_.isPaired)),
          show = extraData.canPaired
        ).render,
        SelectInlineCp.Props(
          value = myData.method,
          label = messages("analysisMethod"),
          name = "method",
          optionMap = methodMap,
          labelWidth = 2,
          inputWidth = 3,
          onChange = FTool.strChange(modifyLens[ViolinPlotSoftData](_.method)),
          questionInfo = messages("analysisMethodInfo")
        ).render,
        FileModalCp.Props(
          show = extraData.fileSelectShow,
          showChange = FTool.extraDataVChange(modifyLens[ExtraData](_.fileSelectShow)),
          softKind = myData.kind,
          exampleFileName = extraData.exampleFileName,
          fileSelect = (v:String)=>SyncIO{extraData.fileSelect(v)},
          request = extraData.request,
          tabs = extraData.tabs
        ).render,
        div(
          className := "form-group form-horizontal",
          marginTop := 0.px,
          div(
            className := "actions col-sm-offset-2 col-sm-2",
            button(`type` := "submit", className := "btn btn-primary", width := "90%", messages("run"))
          )
        )
      )
    )

  }

}
